<?php
require_once "config.php";
require_once "PHPTelnet.php";

// $extra_commands lists extra commands that should be shown in the menus,
// but are not listed in the help screens.
//
$extra_commands = array();

$extra_commands[''] = 'diag wizard';

// $filters provides a way to pretty-print the output of a command.
// Each entry is function that prints the output of a command, which
// is passed as argument.
//
$filters = array();

$filters["voice dialplan list"] = 'filter_dialplan';
$filters["voice stats list"] = 'filter_voice_stats';

if (isset($_POST['mycmd'])) {
    $cmd = $_POST['mycmd'];
    $execute = true;
} else if (isset($_GET['mycmd'])) {
    $cmd = $_GET['mycmd'];
    $execute = false;
} else {
    $cmd = '';
    $execute = false;
}

if (isset($_POST['mydebug'])) {
    $debug = $_POST['mydebug'];
} else if (isset($_GET['mydebug'])) {
    $debug = $_GET['mydebug'];
} else {
    $debug = 0;
}

$telnet = new PHPTelnet();
$result = $telnet->Connect($st_ip, $st_user, $st_password);

if ($result == 0) {
    echo "<html><head>\n";
    echo "<title>TweakTouch - $cmd".($debug ? ' (debug)' : '')."</title>\n";
    echo "<link rel=\"icon\" href=\"tweaktouch.ico\" type=\"image/x-icon\" />\n";
    echo "<link rel=\"stylesheet\" href=\"tweaktouch.css\" type=\"text/css\" />\n";
    echo "</head><body>\n";
    echo "<h1><span class=\"tweak\">tweak</span><span class=\"touch\">touch</span></h1>\n";
    echo "<div id=\"content\">\n";
    if ($cmd == '') {
        echo_result($telnet->welcome);
    } else {
	$telnet->DoCommand("help $cmd", $result);
	parse_help($result);
    }
    echo "</div>\n";
    echo_navigation();
    echo "</body></html>\n";
    // say Disconnect(0); to break the connection without explicitly logging out
    $telnet->Disconnect();
}

function echo_result ($s)
{
    $s = htmlspecialchars($s);
    echo "<code><pre>$s</pre></code>\n";
}

function parse_help ($s)
{
    global $execute, $cmd, $new_cmd, $debug, $telnet, $filters;
    $d = $debug ? '&mydebug=1' : '';
    $c = $cmd == '' ? '' : "$cmd ";
    $new_cmd = $cmd;
    $state = 0;
    $lines = explode("\r\n", $s);
    $current_line = '';
    foreach ($lines as $line) {
    	if ($debug) echo "<br />\nLine: $line<br />\n";
	$line = trim($line);
    	if ($line == "Following commands are available :") {
	    if ($state != 0) echo "</table>\n";
	    echo "<h3>Commands</h3>\n";
	    echo "<table>\n";
	    $state = 1;
	} else if ($line == "Following command groups are available :") {
	    if ($current_line <> '') {
		$current_line = preg_replace('/^([^ ]+) *: (.+)$/', 
		    '<tr><td><a href="index.php?mycmd='.$c.'$1'.$d.'">$1</a></td><td>$2</td></tr>',
		    $current_line);
		echo "  $current_line\n";
	    } 
	    $state = 2;
	} else if ($line == "Parameters :") {
	    if (!$execute) {
                echo "<h3>$lines[0]</h3>\n";
	        echo "<form action=\"index.php\" method=\"post\"><table>\n";
		echo "<input type=\"hidden\" name=\"mycmd\" value=\"$cmd\" />\n";
		if ($debug)
		    echo "<input type=\"hidden\" name=\"mydebug\" value=\"1\" />\n";
	    }
            $syntax = '';
	    $state = 3;
	} else if ($state == 1) {
	    if ($line != '') {
	        if (preg_match('/^[^ ]+ *:/', $line)) {
		    if ($current_line <> '') {
	                $current_line = preg_replace('/^([^ ]+) *: (.+)$/', 
		            '<tr><td><a href="index.php?mycmd='.$c.'$1'.$d.'">$1</a></td><td>$2</td></tr>',
		            $current_line);
	                echo "  $current_line\n";
		    } 
		    $current_line = $line;
		} else {
	            $current_line .= " $line";
		}
	    }
	} else if ($state == 2) {
	} else if ($state == 3) {
	    $line = trim($line);
	    if ($line != '') {
		$syntax .= $line;
		if (parse_parameter($syntax)) {
		    $state = 4;
	        } 
	    }
	} else if ($state == 4) {
	    $line = trim($line);
	    if (preg_match('/^[^ ]+ *=? *</', $line)) {
	        if (!$execute)
	            echo "</td></tr>\n";
		$syntax = $line;
		if (!parse_parameter($syntax)) {
	            $state = 3;
		}
            } else {
	        if (!$execute)
	            echo "$line\n";
	    }
	}
    }
    if ($state == 0) {
        if ($debug) echo "<br />\nCommand: $cmd<br />\n";
	$telnet->DoCommand("$cmd", $result);
	echo_result($result);
    } else if ($state == 1) {
        if ($current_line <> '') {
	    $current_line = preg_replace('/^([^ ]+) *: (.+)$/', 
	        '<tr><td><a href="index.php?mycmd='.$c.'$1'.$d.'">$1</a></td><td>$2</td></tr>',
	        $current_line);
	    echo "  $current_line\n";
        } 
        echo "</table>\n";
    } else if ($state == 2) {
        echo "</table>\n";
    } else {
	if ($execute) {
	    if ($debug) echo "<br />\nCommand: $new_cmd<br />\n";
	    $telnet->DoCommand("$new_cmd", $result);
	    if (isset($filters[$cmd])) {
	        $filters[$cmd]($result);
		if ($debug) echo_result($result);
	    } else {
		echo_result($result);
	    }
	} else {
            if ($state == 4) {
	        echo "</td></tr>\n";
	    }
            echo "</table>\n";
	    echo "<input type=\"submit\" value=\"Go\" />\n";
            echo "</form>\n";
	}
    }
}

function parse_parameter ($s)
{
    global $execute, $new_cmd;

    if ($optional = preg_match('/^\[([^]]+)\]/', $s, $matches))
        $s = $matches[1];

    if (preg_match(  '/^([^ ]+) *=? *<([^>]+)>/', $s, $matches)) {
        $field = $matches[1];
	if ($execute) {
	    if (isset($_POST[$field]))
	        $value = $_POST[$field];
	    else
	        $value = '';
	    if (!($value === ''))
	        $new_cmd .= " $field=$value";
	} else {
	    if (isset($_GET[$field])) 
		$default = $_GET[$field];
	    else
	    	$default = '';
	    if ($optional)
	        echo "<tr><td>[$field]</td><td>";
	    else
	        echo "<tr><td>$field</td><td>";
            $values = $matches[2];
            if (preg_match('/^\{([^{]+)\}$/', $values, $matches)) {
	        $values = explode('|', $matches[1]);
	        echo "<select name=\"$field\">";
		if ($optional) {
		    if ($default == '')
			echo "<option value=\"\" selected>-</option>";
		    else
			echo "<option value=\"\">-</option>";
		}
	        foreach ($values as $value) {
		    if ($value == $default)
		        echo "<option value=\"$value\" selected>$value</option>";
		    else
		        echo "<option value=\"$value\">$value</option>";
	        }
	        echo "</select>";
	    } else {
	        if ($default)
	            echo "<input name=\"$field\" type=\"text\" size=20 value=\"$default\" />";
	        else
	            echo "<input name=\"$field\" type=\"text\" size=20 />";
	    }
	    echo "</td><td>";
	}
	return true;
    } else {
	return false;
    }
}

function filter_dialplan ($s)
{
    global $debug;

    if ($debug) echo_result($s);

    $lines = explode("\r\n", $s);

    echo "<table class=\"dialplan\">\n";
    echo "<caption>Dialplan</caption>\n";
    echo "<thead><tr><th>Prefix</th><th>Default port</th><th>Fallback port</th><th>Priority</th><th>Fallback</th><th>Min. dig.</th><th>Max. dig.</th><th>Pos. mod.</th><th>Rem. dig.</th><th>Insert</th><th>Rescan</th><th>Action</th></tr></thead>\n";
    for ($i = 4; $i < (count($lines) - 1); $i += 2) {
	if (preg_match_all('/(\S+)/', $lines[$i].$lines[$i+1], $m)) {
	    $m = $m[1];
	    echo "<tr><td>$m[0]</td><td>$m[1]</td><td>$m[2]</td><td>$m[3]</td><td>$m[4]</td><td>$m[5]</td><td>$m[6]</td><td>$m[7]</td><td>$m[8]</td>";
	    if (count($m) == 11)
		echo "<td></td><td>$m[9]</td><td>$m[10]</td>";
	    else
		echo "<td>$m[9]</td><td>$m[10]</td><td>$m[11]</td>";
	    echo "</tr>\n";
	}
    }
    echo "</table>\n";
}

function filter_voice_stats ($s)
{
    global $phone2name;
    //
    // Try to match:
    //
    // Total nbr of incoming calls      : 4
    // Successful nbr of incoming calls : 0
    // Missed nbr of incoming calls     : 4
    // Total nbr of outgoing calls      : 65
    // Successful nbr of outgoing calls : 61
    // Failed nbr of outgoing calls     : 4
    //
    if (preg_match('/Total nbr of incoming calls\s*:\s*(\d+)\s+'.
                   'Successful nbr of incoming calls\s*:\s*(\d+)\s+'.
		   'Missed nbr of incoming calls\s*:\s*(\d+)\s+'.
		   'Total nbr of outgoing calls\s*:\s*(\d+)\s+'.
		   'Successful nbr of outgoing calls\s*:\s*(\d+)\s+'.
		   'Failed nbr of outgoing calls\s*:\s*(\d+)/s',
		   $s, $m)) {
        echo "<table class=\"call-numbers\">\n";
	echo "<caption>Number of calls</caption>\n";
	echo "<thead><tr><th></th><th>Total</th><th>Success</th><th>Missed</th></tr></thead>\n";
	echo "<tr><th>Incoming</th><td>$m[1]</td><td>$m[2]</td><td>$m[3]</td></tr>\n";
	echo "<tr><th>Outgoing</th><td>$m[4]</td><td>$m[5]</td><td>$m[6]</td></tr>\n";
	echo "</table>\n";
    }
    if (preg_match('/Detailed statistics/s', $s)) {
	//
        // Try to match:
	//
	// Outgoing call from 0987654321 at FXS1 to 0123456789 via VoIP registered at 08/01/07 11:47:52 (call duration 72 seconds)
	// Mean end-to-end delay            : 0
	// Worst end-to-end delay           : 0
	// Remote packets lost (cumulative) : 0
	// Remote packets lost (ratio)      : 0
	// Remote packets lost (fraction)   : 0
	// Remote mean jitter               : 0
	// Remote worst jitter              : 0
	//
	preg_match_all('/(\w+) (\w+ |)call from (\d+) \w+ (\w+) to (\d+) \w+ (\w+) registered at (\d+.\d+.\d+) (\d+.\d+.\d+)( .call duration (\d+) seconds.\s+'.
	               'Mean end-to-end delay\s*:\s*(\d+)\s+'.
		       'Worst end-to-end delay\s*:\s*(\d+)\s+'.
		       'Remote packets lost .cumulative.\s*:\s*(\d+)\s+'.
		       'Remote packets lost .ratio.\s*:\s*(\d+)\s+'.
		       'Remote packets lost .fraction.\s*:\s*(\d+)\s+'.
		       'Remote mean jitter\s*:\s*(\d+)\s+'.
		       'Remote worst jitter\s*:\s*(\d+)|)/s',
		       $s, $m, PREG_SET_ORDER);
        echo "<table class=\"call-list\">\n";
	echo "<caption>List of calls</caption>\n";
	echo "<tr><thead><th></th><th colspan=2>From</th><th colspan=2>To</th><th colspan=3>When</th><th colspan=2>Delay</th><th colspan=3>Packets lost</th><th colspan=2>Jitter</th></tr>\n";
	echo "<tr><th></th><th>Number</th><th>Int.</th><th>Number</th><th>Int.</th><th>Date</th><th>Time</th><th>Length</th><th>Mean</th><th>Worst</th><th>Cum.</th><th>Ratio</th><th>Frac.</th><th>Mean</th><th>Worst</th></tr></thead>\n";
	foreach ($m as $e) {
	    // Translate phone numbers to names
	    if (isset($phone2name[$e[3]))
	        $e[3] = $phone2name[$e[3];
	    if (isset($phone2name[$e[5]))
	        $e[5] = $phone2name[$e[5];
	    echo "<tr><td>$e[1]</td><td>$e[3]</td><td>$e[4]</td><td>$e[5]</td><td>$e[6]</td><td>$e[7]</td><td>$e[8]</td>";
	    if (count($e) > 10)
		echo "<td>$e[10]</td><td>$e[11]</td><td>$e[12]</td><td>$e[13]</td><td>$e[14]</td><td>$e[15]</td><td>$e[16]</td><td>$e[17]</td>";
	    echo "</tr>\n";
	}
	echo "</table>\n";
    }
}

function echo_navigation()
{
    global $telnet, $debug, $cmd;

    $current = '';
    echo "<ul class=\"trail\">\n";
    if ($debug)
	echo "<li><a href=\"index.php?mydebug=1\">Home</a></li>\n";
    else
	echo "<li><a href=\"index.php\">Home</a></li>\n";
    if ($cmd != '') {
	$t = explode(' ', $cmd);
	$current = $t[0];
	$c = '';
	foreach ($t as $w) {
	    $c = $c == '' ? $w : "$c $w";
	    if ($debug)
		echo "<li><a href=\"index.php?mycmd=$c&mydebug=1\">$w</a></li>\n";
	    else
		echo "<li><a href=\"index.php?mycmd=$c\">$w</a></li>\n";
	}
    }
    echo "</ul>\n";
    $telnet->DoCommand("help", $result);
    echo_menu($result, 'menu', $current);
    if ($cmd != '') {
	$telnet->DoCommand("help $cmd", $result);
	echo_menu($result, 'submenu', '', "$cmd ");
    }
}

function echo_menu ($result, $class, $current, $prefix='')
{
    global $debug, $extra_commands;

    if (!preg_match('/Following command groups are available :/s', $result))
        return;
    $s = preg_replace('/^.*Following command groups are available :/s', '', $result);
    $s = trim($s);
    if (isset($extra_commands[$prefix]))
    	$s = $s == '' ? $extra_commands[$prefix] : 
	                $s.' '.$extra_commands[$prefix];
    if ($s == '')
        return;
    $s = array_unique(preg_split('/\s+/s', $s));
    sort($s);
    $d = $debug ? '&mydebug=1' : '';
    echo "<ul class=\"$class\">\n";
    foreach ($s as $w)  {
        if ($w == $current)
	    echo "<li class=\"current\">";
	else
	    echo "<li>";
	echo "<a href=\"index.php?mycmd=$prefix$w$d\">$w</a></li>\n";
    }
    echo "</ul>\n";
}

?> 
